package com.corewillsoft.fireflies.ui;

import java.util.Set;

import org.anddev.andengine.entity.Entity;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.entity.scene.Scene.IOnSceneTouchListener;
import org.anddev.andengine.input.touch.TouchEvent;

import android.os.Handler;
import android.widget.Toast;

import com.corewillsoft.fireflies.engine.GameEngine;
import com.corewillsoft.fireflies.engine.IGameEngine;
import com.corewillsoft.fireflies.engine.LevelResult;
import com.corewillsoft.fireflies.engine.ResultChecker;
import com.corewillsoft.fireflies.gamelaws.FingerForceLaw;
import com.corewillsoft.fireflies.gamelaws.LawFactory;
import com.corewillsoft.fireflies.gamelaws.LawType;
import com.corewillsoft.fireflies.gameobjects.AreaObject;
import com.corewillsoft.fireflies.gameobjects.Firefly;
import com.corewillsoft.fireflies.gameobjects.GameObject;
import com.corewillsoft.fireflies.gameobjects.Portal;
import com.corewillsoft.fireflies.gameobjects.obstacles.Obstacle;
import com.corewillsoft.fireflies.intent.IntentExtras;
import com.corewillsoft.fireflies.sounds.SoundsManager;
import com.corewillsoft.fireflies.ui.BaseActivity.OnMenuClickedListener;
import com.corewillsoft.fireflies.util.ScreenUtils;

public class GameActivity extends BaseActivity implements IOnSceneTouchListener, IGameEngine, OnMenuClickedListener {

	public enum GameLayerType {
		BACKGROUND,
		FIREFLIES_NOT_ACTIVE,
		FIREFLIES_ACTIVE,
		PORTALS,
		OBSTACLES,
		TOUCH
	}

	private AreaObject gameRestrictedArea;
	private FingerForceLaw fingerForceLaw;
	private int currentLevel;
	private final Handler handler = new Handler();
	private boolean levelFinished;

	@Override
	public void onLoadResources() {
		super.onLoadResources();
	}

	@Override
	public Scene onLoadScene() {
		super.onLoadScene();
		gameRestrictedArea = new AreaObject(0, ScreenUtils.getInstance().getRelativeHeight(), 0, ScreenUtils
				.getInstance().getRelativeWidth());
		GameObject.setGameRestrictedArea(gameRestrictedArea);

		for (int layerNr = 0; layerNr < GameLayerType.values().length; layerNr++) {
			this.scene.attachChild(new Entity());
		}

		scene.setOnSceneTouchListener(this);

		return scene;
	}

	@Override
	public void onLoadComplete() {
		Toast.makeText(this, "Level started!", Toast.LENGTH_LONG).show();
		currentLevel = getIntent().getExtras().getInt(IntentExtras.LEVEL_EXTRA);
		boolean newGame = getIntent().getExtras().getBoolean(IntentExtras.NEW_GAME);
		GameEngine.initInstance(currentLevel, newGame);
		GameEngine.getInstance().start();
		GameEngine.getInstance().setListener(this);
		initGameObjects();
	}

	@Override
	public boolean onSceneTouchEvent(Scene pScene, TouchEvent sceneTouchEvent) {

		float fingerX = (int) sceneTouchEvent.getX();
		float fingerY = (int) sceneTouchEvent.getY();

		switch (sceneTouchEvent.getAction()) {
		case TouchEvent.ACTION_DOWN:
			fingerForceLaw = (FingerForceLaw) LawFactory.getLaw(LawType.FINGER_FORCE);
			GameEngine.getInstance().addLaw(fingerForceLaw);
			fingerForceLaw.setFingerX(fingerX);
			fingerForceLaw.setFingerY(fingerY);
			return true;
		case TouchEvent.ACTION_UP:
			GameEngine.getInstance().removeLaw(fingerForceLaw);
			return true;
		case TouchEvent.ACTION_MOVE:
			if (fingerForceLaw != null) {
				fingerForceLaw.setFingerX(fingerX);
				fingerForceLaw.setFingerY(fingerY);
			}
			return true;
		}
		return false;
	}

	@Override
	protected void onPause() {
		super.onPause();
		if (!levelFinished) {
			GameEngine.getInstance().saveGameLevel();
		}
	}

	@Override
	protected void onStop() {
		super.onStop();
		GameEngine.getInstance().stop();
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
		GameEngine.getInstance().stop();
	}

	@Override
	public void onLevelFinished() {
		handler.post(new Runnable() {

			@Override
			public void run() {
				levelFinished = true;

				Set<Firefly> fireflies = GameEngine.getInstance().getFireflies();
				LevelResult levelResult = ResultChecker.checkResult(fireflies, currentLevel);
				if (levelResult.equals(LevelResult.LOST)) {
					SoundsManager.getInstance().playGameOver();
				} else if (levelResult.equals(LevelResult.WON)) {
					GameEngine.getInstance().saveFinishedGameLevel();
					SoundsManager.getInstance().playLevelFinished();
				} else if (levelResult.equals(LevelResult.GAME_FINISHED)) {
					SoundsManager.getInstance().playGameFinished();
				}
				showResultMenu(levelResult, GameActivity.this);
				GameEngine.getInstance().stop();
			}
		});
	}

	private void initGameObjects() {
		Set<Firefly> fireflies = GameEngine.getInstance().getFireflies();
		for (Firefly firefly : fireflies) {
			firefly.setLayerType(GameLayerType.FIREFLIES_ACTIVE);
			scene.getChild(GameLayerType.FIREFLIES_ACTIVE.ordinal()).attachChild(firefly);
		}

		Set<Obstacle> obstacles = GameEngine.getInstance().getObstacles();
		for (Obstacle obstacle : obstacles) {
			obstacle.setLayerType(GameLayerType.OBSTACLES);
			scene.getChild(GameLayerType.OBSTACLES.ordinal()).attachChild(obstacle);
		}

		Set<Portal> portals = GameEngine.getInstance().getPortals();
		for (Portal portal : portals) {
			portal.setLayerType(GameLayerType.PORTALS);
			scene.getChild(GameLayerType.PORTALS.ordinal()).attachChild(portal);
		}
	}

	@Override
	protected void resumeGame() {
		GameEngine.getInstance().resume();
	}

	@Override
	public void pauseGame() {
		GameEngine.getInstance().pause();
	}

	private void initLevel(int level, boolean newGame) {
		levelFinished = false;
		GameEngine.getInstance().stop();
		scene.reset();
		GameEngine.initInstance(currentLevel, newGame);
		GameEngine.getInstance().start();
		GameEngine.getInstance().setListener(this);
		initGameObjects();
	}

	@Override
	public boolean onMenuClicked(MENU type) {
		switch (type) {
		case CONTINUE:
			resumeGame();
			return true;
		case NEXT_LEVEL:
			currentLevel++;
			initLevel(currentLevel, true);
			return true;
		case RESTART:
			initLevel(currentLevel, true);
			return true;
		case SAVE:
			GameEngine.getInstance().saveGameLevel();
			return true;
		case RESTORE:
			initLevel(currentLevel, false);
			return true;
		default:
			return false;
		}
	}

	@Override
	protected void onHardKeyMenuPressed() {
		showGameMenu(this);
	}
}
